package middle.ground.db;

import middle.ground.core.annotation.Column;
import middle.ground.core.annotation.Persist;
import middle.ground.core.annotation.Table;
import middle.ground.utils.SingletonObject;
import middle.ground.utils.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.lob.DefaultLobHandler;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author jrl
 * @author jrl
 * @date 2020-12-01
 */
public abstract class MysqlBaseDaoImpl<T> implements BaseDao<T> {

	private static final Logger logger = LoggerFactory.getLogger(MysqlBaseDaoImpl.class);

	@Autowired
	protected JdbcTemplate jdbcTemplate;

	private ResultSetExtractor<T> defaultEntityResultSetExtractor = this::resolveOne;

	private ResultSetExtractor<List<T>> defaultListResultSetExtractor = this::resolve;

	/**
	 * 定义一个T的类对象，用于获取泛型的class
	 */
	private Class<T> entityClass;

	/**
	 * 通过反射获取T实际的Class对象
	 *
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Class<T> getEntityClass() {
		if (null == entityClass) {
			entityClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		}
		return entityClass;
	}

	@Override
	public T add(T t) {
		Table table = getTableAnnotation();
		String idField = table.idField();
//		String sequence = table.sequence();
//		if (StringUtils.isNotBlank(sequence)) {
//			Integer id = jdbcTemplate.queryForObject("SELECT " + sequence + ".NEXTVAL FROM DUAL", Integer.class);
//			try {
//				entityClass.getDeclaredMethod(getSetter(idField), Integer.class).invoke(t, id);
//			} catch (Exception e) {
//				throw new RuntimeException("设置主键失败[" + entityClass.getName() + "#" + idField, e);
//			}
//		}

		StringBuilder valueSql = new StringBuilder();
		StringBuilder sql = new StringBuilder("INSERT INTO ").append("`").append(table.table()).append("`").append(" (");

		Field[] fields = entityClass.getDeclaredFields();
		final List<Object> values = new ArrayList<>();
		f:
		for (Field field : fields) {
			if (isaStatic(field)) {
				continue;
			}


			Persist persist = field.getAnnotation(Persist.class);
			if (null != persist) {
				String[] persistValues = persist.value();
				for (String persistValue : persistValues) {
					if (Persist.UNINSERTABLE.equals(persistValue)) {
						continue f;
					}
				}
			}

			String fieldName = field.getName();
			if ("updateUserId".equals(fieldName) || isaStatic(field)) {
				continue;
			}
			if ("createTime".equals(fieldName) || "updateTime".equals(fieldName)) {
				try {
					entityClass.getDeclaredMethod(getSetter(fieldName), Date.class).invoke(t, new Date());
				} catch (Exception e) {
					throw new RuntimeException("设置创建时间失败[" + entityClass.getName() + "#" + idField, e);
				}
			}

			String temp = null;
			boolean escape = false;
			Column column = field.getAnnotation(Column.class);
			if (null != column && StringUtil.isNotBlank(column.value())) {
				temp = column.value();
			}
			if (StringUtils.isBlank(temp)) {
				temp = translateField2Column(fieldName);
			}

			try {
				Object value = entityClass.getDeclaredMethod(getGetter(fieldName)).invoke(t);
				if (column != null && value != null && column.isJson()) {
					value = SingletonObject.OBJECT_MAPPER.writeValueAsString(value);
				}
				if (null != value) {
					values.add(value);
					if (escape) {
						sql.append("\"").append(temp).append("\",");
					} else {
						sql.append("`").append(temp).append("`").append(",");
					}
					valueSql.append("?,");
				}
			} catch (Exception e) {
				logger.error("调用[{} # {}]的Getter方法异常{}", entityClass.getName(), fieldName, e.getMessage());
			}
		}

		int len = sql.length() - 1;
		if (sql.lastIndexOf(StringUtil.COMMA) != len) {
			throw new RuntimeException("没有要插入的数据");
		}

		sql.deleteCharAt(len);
		valueSql.deleteCharAt(valueSql.length() - 1);
		sql.append(") VALUES (").append(valueSql).append(")");

		jdbcTemplate.update(sql.toString(), ps -> {
			for (int i = 0; i < values.size(); i++) {
				Object value = values.get(i);
				if (value instanceof java.sql.Date) {
					ps.setDate(i + 1, (java.sql.Date) value);
				} else if (value instanceof Timestamp) {
					ps.setTimestamp(i + 1, (Timestamp) value);
				} else if (value instanceof Date) {
					ps.setTimestamp(i + 1, new Timestamp(((Date) value).getTime()));
				} else {
					ps.setObject(i + 1, value);
				}
			}
		});
		try {
			if (StringUtils.isNotBlank(idField)) {
				entityClass.getDeclaredMethod(getSetter(idField), Integer.class).invoke(t, jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Integer.class));
			}
		} catch (Exception e) {
			logger.error("回设ID失败[" + entityClass.getName() + "#" + idField + "]：" + e.getMessage());
		}
		return t;
	}

	private boolean isaStatic(Field field) {
		return Modifier.isStatic(field.getModifiers());
	}

	@Override
	public void batchAdd(List<T> ts) {
		batchAdd(ts, 2000);
	}

	@Override
	public void batchAdd(List<T> ts, int batchSize) {
		Connection connection = null;
		PreparedStatement statement = null;
		try {
			DataSource dataSource = jdbcTemplate.getDataSource();
			if (dataSource == null) {
				throw new RuntimeException("数据库连接异常");
			}
			connection = dataSource.getConnection();
			connection.setAutoCommit(false);
			statement = connection.prepareStatement(getInsertSql());

			int count = 0;
			for (T t : ts) {
				List<Object> values = getInsertParam(t);
				for (int i = 0; i < values.size(); i++) {
					Object value = values.get(i);
					if (value instanceof java.sql.Date) {
						statement.setDate(i + 1, (java.sql.Date) value);
					} else if (value instanceof Timestamp) {
						statement.setTimestamp(i + 1, (Timestamp) value);
					} else if (value instanceof Date) {
						statement.setTimestamp(i + 1, new Timestamp(((Date) value).getTime()));
					} else {
						statement.setObject(i + 1, value);
					}
				}
				statement.addBatch();

				if (++count % batchSize == 0) {
					statement.executeBatch();
					connection.commit();
				}
			}
			statement.executeBatch();
			connection.commit();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			if (statement != null) {
				try {
					statement.close();
				} catch (SQLException e) {
					logger.error(e.getMessage(), e);
				}
			}
			if (connection != null) {
				try {
					connection.close();
				} catch (SQLException e) {
					logger.error(e.getMessage(), e);
				}
			}
		}
	}

	@Override
	public int update(T t) {
		return update(t, false);
	}

	@Override
	public int updateNotNull(T t) {
		return update(t, true);
	}

	private int update(T t, boolean updateNotNull) {
		Table table = getTableAnnotation();
		String idField = table.idField();
		StringBuilder sql = new StringBuilder("UPDATE ").append("`").append(table.table()).append("`").append(" SET ");

		Field[] fields = entityClass.getDeclaredFields();
		final List<Object> values = new ArrayList<>();
		f:
		for (Field field : fields) {
			String fieldName = field.getName();
			if (idField.equals(fieldName) || "createTime".equals(fieldName) || "createUserId".equals(fieldName) || isaStatic(field)) {
				continue;
			}


			Persist persist = field.getAnnotation(Persist.class);
			if (null != persist) {
				String[] persistValues = persist.value();
//				boolean unupdatable = false;
				for (String persistValue : persistValues) {
					if (Persist.UNUPDATABLE.equals(persistValue)) {
//						unupdatable = true;
//						break;
						continue f;
					}
				}
//				if (unupdatable) {
//					continue;
//				}
			}

			if ("updateTime".equals(fieldName)) {
				try {
					entityClass.getDeclaredMethod(getSetter(fieldName), Date.class).invoke(t, new Date());
				} catch (Exception e) {
					throw new RuntimeException("设置最后更新时间失败[" + entityClass.getName() + "#" + idField, e);
				}
			}

			String temp = null;
			boolean escape = false;
			Column column = field.getAnnotation(Column.class);
			if (null != column && StringUtil.isNotBlank(column.value())) {
				temp = column.value();
			}
			if (StringUtils.isBlank(temp)) {
				temp = translateField2Column(fieldName);
			}

			try {
				Object value = entityClass.getDeclaredMethod(getGetter(fieldName)).invoke(t);
				if (column != null && value != null && column.isJson()) {
					value = SingletonObject.OBJECT_MAPPER.writeValueAsString(value);
				}
				if (null == value) {
					if (updateNotNull) {
						continue;
					}
				}

				values.add(value);
				if (escape) {
					sql.append("\"").append(temp).append("\"=?,");
				} else {
					sql.append("`").append(temp).append("`").append("=?,");
				}
			} catch (Exception e) {
				logger.error("调用[{} # {}]的Getter方法异常{}", entityClass.getName(), fieldName, e.getMessage());
			}
		}

		int len = sql.length() - 1;
		if (sql.lastIndexOf(StringUtil.COMMA) != len) {
			throw new RuntimeException("没有要更新的数据");
		}
		sql.deleteCharAt(len);

		String temp = table.idColumn();
//		if (null == temp) {
//			temp = translateField2Column(idField);
//		}
		try {
			values.add(entityClass.getDeclaredMethod(getGetter(idField)).invoke(t));
		} catch (Exception e) {
			logger.error("获取ID失败[{} # {}]: {}", entityClass.getName(), idField, e.getMessage());
		}

		sql.append(" WHERE ").append(temp).append("=?");

		return jdbcTemplate.update(sql.toString(), ps -> {
			for (int i = 0; i < values.size(); i++) {
				Object value = values.get(i);
				if (value instanceof java.sql.Date) {
					ps.setDate(i + 1, (java.sql.Date) value);
				} else if (value instanceof Timestamp) {
					ps.setTimestamp(i + 1, (Timestamp) value);
				} else if (value instanceof Date) {
					ps.setTimestamp(i + 1, new Timestamp(((Date) value).getTime()));
				} else {
					ps.setObject(i + 1, value);
				}
			}
		});
	}

	@Override
	public void merge(T t) {
		Table table = getTableAnnotation();
		String idField = table.idField();
		Object id = null;
		try {
			id = entityClass.getDeclaredMethod(getGetter(idField)).invoke(t);
		} catch (Exception e) {
			logger.error("获取ID失败[{} # {}]: {}", entityClass.getName(), idField, e.getMessage());
		}
		if (Integer.valueOf(0).equals(id)) {
			id = null;
		}

		if (null == id) {
			add(t);
		} else {
			update(t);
		}
	}

	@Override
	public int delete(final Integer id) {
		Table table = getTableAnnotation();
		String temp = table.idColumn();
//		if (null == temp) {
//			temp = translateField2Column(table.idField());
//		}

		return jdbcTemplate.update("DELETE FROM `" + table.table() + "` WHERE " + temp + "=?", ps -> ps.setInt(1, id));
	}

	@Override
	public T load(Integer id) {
		Table table = getTableAnnotation();
		String temp = table.idColumn();
//		if (null == temp) {
//			temp = translateField2Column(table.idField());
//		}

		return jdbcTemplate.query("SELECT * FROM `" + table.table() + "` WHERE " + temp + "=?", new Object[]{id}, defaultEntityResultSetExtractor);
	}


	@Override
	public T get(String sql) {
		return jdbcTemplate.query(sql, defaultEntityResultSetExtractor);
	}

	@Override
	public <C> C getEntity(Class<C> clazz, String sql) {
		return jdbcTemplate.query(sql, getEntityResultSetExtractor(clazz));
	}

	@Override
	public T get(String sql, final Object... params) {
		return jdbcTemplate.query(sql, params, defaultEntityResultSetExtractor);
	}

	@Override
	public <C> C getEntity(Class<C> clazz, String sql, Object... params) {
		return jdbcTemplate.query(sql, params, getEntityResultSetExtractor(clazz));
	}

	@Override
	public T get(String sql, Map<String, Object> alias) {
		return new NamedParameterJdbcTemplate(jdbcTemplate).query(sql, alias, defaultEntityResultSetExtractor);
	}

	@Override
	public <C> C getEntity(Class<C> clazz, String sql, Map<String, Object> alias) {
		return new NamedParameterJdbcTemplate(jdbcTemplate).query(sql, alias, getEntityResultSetExtractor(clazz));
	}

	@Override
	public int update(String sql) {
		return jdbcTemplate.update(sql);
	}

	@Override
	public int update(String sql, Object... params) {
		return jdbcTemplate.update(sql, params);
	}

	@Override
	public int update(String sql, Map<String, Object> alias) {
		return new NamedParameterJdbcTemplate(jdbcTemplate).update(sql, alias);
	}

	@Override
	public List<T> list(String sql) {
		return jdbcTemplate.query(sql, defaultListResultSetExtractor);
	}

	@Override
	public <C> List<C> listEntity(Class<C> clazz, String sql) {
		return jdbcTemplate.query(sql, getListResultSetExtractor(clazz));
	}

	@Override
	public List<T> list(String sql, Object... params) {
		return jdbcTemplate.query(sql, params, defaultListResultSetExtractor);
	}

	@Override
	public <C> List<C> listEntity(Class<C> clazz, String sql, Object... params) {
		return jdbcTemplate.query(sql, params, getListResultSetExtractor(clazz));
	}

	@Override
	public List<T> list(String sql, Map<String, Object> alias) {
		return new NamedParameterJdbcTemplate(jdbcTemplate).query(sql, alias, defaultListResultSetExtractor);
	}

	@Override
	public <C> List<C> listEntity(Class<C> clazz, String sql, Map<String, Object> alias) {
		return new NamedParameterJdbcTemplate(jdbcTemplate).query(sql, alias, getListResultSetExtractor(clazz));
	}

	@Override
	public Pagination<T> page(String sql, int page, int limit, Object... params) {
		if (page < 1) {
			page = 1;
		}
		if (limit < 1) {
			limit = 10;
		}

		Object[] temp = getParams(page, limit, params);

		return new Pagination<T>(page, limit, list(sql + " limit ?,?", temp));
	}

	@Override
	public <C> Pagination<C> pageEntity(Class<C> clazz, String sql, int page, int limit, Object... params) {
		if (page < 1) {
			page = 1;
		}
		if (limit < 1) {
			limit = 10;
		}

		Object[] temp = getParams(page, limit, params);
		return new Pagination<>(page, limit, listEntity(clazz, sql + " limit ?,?", temp));
	}

	private Object[] getParams(int page, int limit, Object[] params) {
		Object[] temp;
		if (params != null) {
			temp = new Object[params.length + 2];
			System.arraycopy(params, 0, temp, 0, params.length);
		} else {
			temp = new Object[2];
		}

		temp[temp.length - 1] = limit;
		temp[temp.length - 2] = (page - 1) * limit;
		return temp;
	}

	@Override
	public Integer count() {
		return jdbcTemplate.query("SELECT COUNT(*) AS c FROM " + getTableAnnotation().table(), rs -> {
			if (!rs.next()) {
				return 0;
			}

			return rs.getInt("c");
		});
	}

	@Override
	public boolean existTable(String tableName) {
		return count("SELECT COUNT(1) FROM information_schema.TABLES WHERE table_name=?", tableName) > 0;
	}

	@Override
	public Integer count(String sql, Object... params) {
		return jdbcTemplate.query(sql, params, rs -> {
			if (!rs.next()) {
				return 0;
			}

			return rs.getInt(1);
		});
	}

	@Override
	public Long sum(String sql, Object... params) {
		return jdbcTemplate.query(sql, params, rs -> {
			if (!rs.next()) {
				return Long.valueOf(0);
			}

			return rs.getLong(1);
		});
	}

	private String getInsertSql() {
		StringBuilder sql = new StringBuilder("INSERT INTO ").append(getTableAnnotation().table()).append(" (");

		int fieldCount = 0;
		Field[] fields = entityClass.getDeclaredFields();
		for (Field field : fields) {
			if (isaStatic(field)) {
				continue;
			}

			Persist persist = field.getAnnotation(Persist.class);
			if (null != persist) {
				String[] persistValues = persist.value();
				boolean uninsertable = false;
				for (String persistValue : persistValues) {
					if (Persist.UNINSERTABLE.equals(persistValue)) {
						uninsertable = true;
						break;
					}
				}
				if (uninsertable) {
					continue;
				}
			}

			String temp = null;
			boolean escape = false;
			Column column = field.getAnnotation(Column.class);
			if (null != column && StringUtil.isNotBlank(column.value())) {
				temp = column.value();
			}
			if (StringUtils.isBlank(temp)) {
				temp = translateField2Column(field.getName());
			}

			if (escape) {
				sql.append("\"").append(temp).append("\",");
			} else {
				sql.append(temp).append(",");
			}
			fieldCount++;
		}

		if (fieldCount == 0) {
			throw new RuntimeException("没有要插入的数据");
		}

		sql.deleteCharAt(sql.length() - 1);
		sql.append(") VALUES (?");
		for (int i = 1; i < fieldCount; i++) {
			sql.append(",?");
		}
		sql.append(")");

		return sql.toString();
	}

	private List<Object> getInsertParam(T t) {
		Table table = getTableAnnotation();
		String idField = table.idField();
//		String sequence = table.sequence();
//		if (StringUtils.isNotBlank(sequence)) {
//			Integer id = jdbcTemplate.queryForObject("SELECT " + sequence + ".NEXTVAL FROM DUAL", Integer.class);
//			try {
//				entityClass.getDeclaredMethod(getSetter(idField), Integer.class).invoke(t, id);
//			} catch (Exception e) {
//				throw new RuntimeException("设置主键失败[" + entityClass.getName() + "#" + idField, e);
//			}
//		}

		final List<Object> values = new ArrayList<>();
		Field[] fields = entityClass.getDeclaredFields();
		for (Field field : fields) {
			if (isaStatic(field)) {
				continue;
			}


			Persist persist = field.getAnnotation(Persist.class);
			if (null != persist) {
				String[] persistValues = persist.value();
				boolean uninsertable = false;
				for (String persistValue : persistValues) {
					if (Persist.UNINSERTABLE.equals(persistValue)) {
						uninsertable = true;
						break;
					}
				}
				if (uninsertable) {
					continue;
				}
			}

			String fieldName = field.getName();
			if ("createTime".equals(fieldName) || "updateTime".equals(fieldName)) {
				try {
					entityClass.getDeclaredMethod(getSetter(fieldName), Date.class).invoke(t, new Date());
				} catch (Exception e) {
					throw new RuntimeException("设置创建时间或最后更新时间失败[" + entityClass.getName() + "#" + idField, e);
				}
			}

			Column column = field.getAnnotation(Column.class);
			try {
				Object value = entityClass.getDeclaredMethod(getGetter(fieldName)).invoke(t);
				if (column != null && value != null && column.isJson()) {
					value = SingletonObject.OBJECT_MAPPER.writeValueAsString(value);
				}
				values.add(value);
			} catch (Exception e) {
				logger.error("调用[{} # {}]的Getter方法异常{}", entityClass.getName(), fieldName, e.getMessage());
			}
		}

		return values;
	}

	private Table getTableAnnotation() {
		getEntityClass();

		Table table = entityClass.getAnnotation(Table.class);
		if (null == table) {
			throw new RuntimeException(entityClass.getName() + "不符合实体规范，请添加@Table注解!");
		}
		String tableName = table.table();
		if ("".equals(tableName.trim()) || tableName.contains(StringUtil.BLANK)) {
			throw new RuntimeException(entityClass.getName() + "不符合实体规范，请检查@Table注解的table值:不能为空,不能包含空格");
		}
//		String idField = table.idField();
//		if ("".equals(idField.trim()) || idField.contains(StringUtil.BLANK)) {
//			throw new RuntimeException(entityClass.getName() + "不符合实体规范，请检查@Table注解的id值:不能为空,不能包含空格");
//		}

		return table;
	}

	private T resolveOne(ResultSet rs) throws SQLException {
		if (!rs.next()) {
			return null;
		} else {
			T t;

			try {
				t = this.getEntityClass().newInstance();
			} catch (Exception var22) {
				throw new RuntimeException(var22);
			}

			Table table = this.getTableAnnotation();
			String idField = table.idField();
			Field[] fields = this.entityClass.getDeclaredFields();
			Map<String, Field> columnFieldMap = new HashMap<>(fields.length);

			for (Field field : fields) {
				if (!isaStatic(field)) {
					String fieldName = field.getName();
					String column;
					if (idField.equals(fieldName)) {
						column = table.idColumn();
//						if (null == column) {
//							column = translateField2Column(idField);
//						}

						columnFieldMap.put(column, field);
					} else {
						column = null;
						boolean escape = false;
						Column columnAnnotation = field.getAnnotation(Column.class);
						if (null != columnAnnotation) {
							column = columnAnnotation.value();
						}

						if (StringUtils.isBlank(column) || escape) {
							column = translateField2Column(fieldName);
						}

						columnFieldMap.put(column, field);
					}
				}
			}

			ResultSetMetaData metaData = rs.getMetaData();
			int columnCount = metaData.getColumnCount();
			Map<String, String> columnClassMap = new HashMap<>();
			Field field;
			for (int i = 1; i <= columnCount; ++i) {
				String columnName = metaData.getColumnLabel(i).toLowerCase();
				String columnClassName = metaData.getColumnClassName(i);
				columnClassMap.put(columnName, columnClassName);
			}
			for (Map.Entry<String, String> m : columnClassMap.entrySet()) {
				String columnName = m.getKey();
				String columnClassName = m.getValue();
				Object value;
				if (columnClassName.toUpperCase().contains("[B")) {
					value = new DefaultLobHandler().getClobAsString(rs, columnName);
				} else {
					value = rs.getObject(columnName);
				}
				if (null != value) {
					field = columnFieldMap.get(columnName);
					if (null == field) {
//						logger.error("Class[" + this.entityClass.getName() + "]中未发现数据库列[" + columnName + "]对应的字段!");
					} else {
						String fieldName = field.getName();

						Class<?> fieldType = field.getType();
						Class<?> valueType = value.getClass();
						Column column = field.getAnnotation(Column.class);
						boolean isDatabaseEnum = false;
						if (fieldType != valueType) {
							if (column != null && column.isJson()) {
								try {
									value = SingletonObject.OBJECT_MAPPER.readValue((String) value, field.getType());
								} catch (Exception e) {
									throw new RuntimeException(e);
								}
							} else if (Clob.class.isAssignableFrom(valueType)) {
								try {
									value = new DefaultLobHandler().getClobAsString(rs, columnName);
								} catch (SQLException e) {
									value = "";
									logger.error("Class[{}]中数据库列[{}]CLOB字段转换错误 !", this.entityClass.getName(), columnName);
								}
							} else {
								// logger.warn("cast value {},{},{},{}",fieldName,fieldType,valueType,value);
								value = this.castValue(fieldType, valueType, value);
							}
						}

						try {
							this.entityClass.getDeclaredMethod(getSetter(fieldName), fieldType).invoke(t, value);
						} catch (Exception var22) {
							logger.error("调用[{}#{}]的Setter方法异常：{}", this.entityClass.getName(), fieldName, var22.getMessage());
						}
					}
				}
			}


			return t;
		}
	}

	private List<T> resolve(ResultSet rs) throws SQLException {
		this.getEntityClass();
		Table table = this.getTableAnnotation();
		String idField = table.idField();
		Field[] fields = this.entityClass.getDeclaredFields();
		Map<String, Field> columnFieldMap = new HashMap<>(fields.length);

		Field field;
		for (Field item : fields) {
			field = item;
			if (!isaStatic(field)) {
				String fieldName = field.getName();
				String column;
				if (idField.equals(fieldName)) {
					column = table.idColumn();
//					if (null == column) {
//						column = translateField2Column(idField);
//					}

					columnFieldMap.put(column, field);
				} else {
					column = null;
					boolean escape = false;
					Column columnAnnotation = field.getAnnotation(Column.class);
					if (null != columnAnnotation) {
						column = columnAnnotation.value();
					}

					if (StringUtils.isBlank(column) || escape) {
						column = translateField2Column(fieldName);
					}

					columnFieldMap.put(column, field);
				}
			}
		}


		ResultSetMetaData metaData = rs.getMetaData();
		int columnCount = metaData.getColumnCount();
		Map<String, String> columnClassMap = new HashMap<>();

		for (int i = 1; i <= columnCount; ++i) {
			String columnName = metaData.getColumnLabel(i).toLowerCase();
			String columnClassName = metaData.getColumnClassName(i);
			columnClassMap.put(columnName, columnClassName);
		}
		List<T> result = new ArrayList<>();
		while (rs.next()) {
			T t;
			try {
				t = this.entityClass.newInstance();
			} catch (Exception var23) {
				throw new RuntimeException(var23);
			}
			for (Map.Entry<String, String> m : columnClassMap.entrySet()) {
				String columnName = m.getKey();
				String columnClassName = m.getValue();
				Object value;
				if (columnClassName.toUpperCase().contains("[B")) {
					value = new DefaultLobHandler().getClobAsString(rs, columnName);
				} else {

					value = rs.getObject(columnName);
				}
				if (null != value) {
					field = columnFieldMap.get(columnName);
					if (null == field) {
//						logger.error("Class[{}]中未发现数据库列[{}]对应的字段!", this.entityClass.getName(), columnName);
					} else {
						String fieldName = field.getName();

						Class<?> fieldType = field.getType();
						Class<?> valueType = value.getClass();
						Column column = field.getAnnotation(Column.class);
						boolean isDatabaseEnum = false;
						if (fieldType != valueType) {
							if (column != null && column.isJson()) {
								try {
									value = SingletonObject.OBJECT_MAPPER.readValue((String) value, field.getType());
								} catch (Exception e) {
									throw new RuntimeException(e);
								}
							} else if (Clob.class.isAssignableFrom(valueType)) {

								try {
									value = new DefaultLobHandler().getClobAsString(rs, columnName);
								} catch (SQLException e) {
									value = "";
									logger.error("Class[{}]中数据库列[{}]CLOB字段转换错误 !", this.entityClass.getName(), columnName);
								}
							}
							// logger.warn("cast value {},{},{},{}",fieldName,fieldType,valueType,value);
							value = this.castValue(fieldType, valueType, value);
						}

						try {
							this.entityClass.getDeclaredMethod(getSetter(fieldName), fieldType).invoke(t, value);
						} catch (Exception var22) {
							logger.error("调用[{}#{}]的Setter方法异常：{}", this.entityClass.getName(), fieldName, var22.getMessage());
						}
					}
				}
			}
			result.add(t);
		}
		return result;
	}

	private Object castValue(Class<?> fieldType, Class<?> valueType, Object value) {
		if (fieldType == Integer.class) {
			if (Long.class == valueType) {
				value = ((Long) value).intValue();
			} else if (Float.class == valueType) {
				value = ((Float) value).intValue();
			} else if (Double.class == valueType) {
				value = ((Double) value).intValue();
			} else if (BigDecimal.class == valueType) {
				value = ((BigDecimal) value).intValue();
			} else if (Timestamp.class == valueType) {
				value = (int) (((Date) value).getTime());
			} else if (String.class == valueType) {
				value = Integer.valueOf((String) value);
			} else if (Boolean.class == valueType) {
				value = ((Boolean) value) ? 1 : 0;
			} else if (BigInteger.class == valueType) {
				value = ((BigInteger) value).intValue();
			}
		} else if (fieldType == Long.class) {
			if (Integer.class == valueType) {
				value = ((Integer) value).longValue();
			} else if (Float.class == valueType) {
				value = ((Float) value).longValue();
			} else if (Double.class == valueType) {
				value = ((Double) value).longValue();
			} else if (BigDecimal.class == valueType) {
				value = ((BigDecimal) value).longValue();
			} else if (Timestamp.class == valueType) {
				value = ((Date) value).getTime();
			} else if (String.class == valueType) {
				value = Long.valueOf((String) value);
			} else if (Boolean.class == valueType) {
				value = ((Boolean) value) ? 1 : 0;
			} else if (BigInteger.class == valueType) {
				value = ((BigInteger) value).longValue();
			}
		} else if (fieldType == Float.class) {
			if (Integer.class == valueType) {
				value = ((Integer) value).floatValue();
			} else if (Long.class == valueType) {
				value = ((Long) value).floatValue();
			} else if (Double.class == valueType) {
				value = ((Double) value).floatValue();
			} else if (BigDecimal.class == valueType) {
				value = ((BigDecimal) value).floatValue();
			} else if (Timestamp.class == valueType) {
				value = ((Date) value).getTime();
			} else if (String.class == valueType) {
				value = Float.valueOf((String) value);
			} else if (Boolean.class == valueType) {
				value = ((Boolean) value) ? 1 : 0;
			} else if (BigInteger.class == valueType) {
				value = ((BigInteger) value).floatValue();
			}
		} else if (fieldType == Double.class) {
			if (Float.class == valueType) {
				value = ((Float) value).doubleValue();
			} else if (BigDecimal.class == valueType) {
				value = ((BigDecimal) value).doubleValue();
			} else if (Integer.class == valueType) {
				value = ((Integer) value).doubleValue();
			} else if (Long.class == valueType) {
				value = ((Long) value).doubleValue();
			} else if (Timestamp.class == valueType) {
				value = ((Date) value).getTime();
			} else if (String.class == valueType) {
				if (StringUtils.isNotBlank((String) value)) {
					value = Double.valueOf((String) value);
				}
			} else if (Boolean.class == valueType) {
				value = ((Boolean) value) ? 1 : 0;
			} else if (BigInteger.class == valueType) {
				value = ((BigInteger) value).doubleValue();
			}
		} else if (fieldType == BigDecimal.class) {
			if (Integer.class == valueType) {
				value = BigDecimal.valueOf((Integer) value);
			} else if (Long.class == valueType) {
				value = BigDecimal.valueOf((Long) value);
			} else if (Float.class == valueType) {
				value = BigDecimal.valueOf((Float) value);
			} else if (Double.class == valueType) {
				value = BigDecimal.valueOf((Double) value);
			} else if (Timestamp.class == valueType) {
				value = BigDecimal.valueOf(((Date) value).getTime());
			} else if (String.class == valueType) {
				value = BigDecimal.valueOf(Double.parseDouble((String) value));
			} else if (Boolean.class == valueType) {
				value = BigDecimal.valueOf(((Boolean) value) ? 1 : 0);
			} else if (BigInteger.class == valueType) {
				value = BigDecimal.valueOf(((BigInteger) value).doubleValue());
			}
		} else if (fieldType == BigInteger.class) {
			if (Integer.class == valueType) {
				value = BigInteger.valueOf((Integer) value);
			} else if (Long.class == valueType) {
				value = BigInteger.valueOf((Long) value);
			} else if (Float.class == valueType) {
				value = BigInteger.valueOf(((Float) value).intValue());
			} else if (Double.class == valueType) {
				value = BigInteger.valueOf(((Double) value).longValue());
			} else if (Timestamp.class == valueType) {
				value = BigInteger.valueOf(((Date) value).getTime());
			} else if (String.class == valueType) {
				value = BigInteger.valueOf(Double.valueOf((String) value).longValue());
			} else if (Boolean.class == valueType) {
				value = BigInteger.valueOf(((Boolean) value) ? 1 : 0);
			} else if (BigDecimal.class == valueType) {
				value = BigInteger.valueOf(((BigDecimal) value).longValue());
			}
		} else if (fieldType == Date.class) {
			if (Integer.class == valueType) {
				value = new Date((Integer) value);
			} else if (Long.class == valueType) {
				value = new Date((Long) value);
			} else if (Float.class == valueType) {
				value = new Date(((Float) value).longValue());
			} else if (Double.class == valueType) {
				value = new Date(((Double) value).longValue());
			} else if (String.class == valueType) {
				value = new Date((String) value);
			} else if (Boolean.class == valueType) {
				// 布尔true代表当前时间，false代表null
				value = ((Boolean) value) ? new Date() : null;
			} else if (BigDecimal.class == valueType) {
				value = new Date(((BigDecimal) value).longValue());
			}
		} else if (fieldType == String.class) {
			value = value.toString();
		}

		return value;
	}

	private static String getGetter(String fieldName) {
		return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
	}

	private static String getSetter(String fieldName) {
		return "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
	}

	/**
	 * 将实体字段转换成表字段
	 *
	 * @param name
	 * @return
	 */
	private static String translateField2Column(String name) {
		StringBuilder result = new StringBuilder();
		char[] chars = name.toCharArray();
		for (int i = 0; i < chars.length; i++) {
			char c = chars[i];
			if (i == 0) {
				if (c >= 'A' && c <= 'Z') {
					result.append((char) (chars[i] + 32));
				} else {
					result.append(c);
				}
			} else {
				if (c >= 'A' && c <= 'Z') {
					result.append("_").append((char) (chars[i] + 32));
				} else {
					result.append(c);
				}
			}
		}

		return result.toString();
	}

	private <C> ResultSetExtractor<C> getEntityResultSetExtractor(Class<C> clazz) {
		return rs -> {

			if (!rs.next()) {
				return null;
			} else {
//				Class<C> entityClass;
//				try {
//					entityClass = Class.forName(clazz.getName());
//				} catch (ClassNotFoundException e) {
//					logger.error(clazz.getName() + "类不存在 " + e.getMessage());
//					throw new NotFoundException(clazz.getName() + "类不存在 ");
//				}
				C t;
				try {
					t = clazz.newInstance();
				} catch (Exception var22) {
					throw new RuntimeException(var22);
				}

				Field[] fields = clazz.getDeclaredFields();
				Map<String, Field> columnFieldMap = new HashMap<>(fields.length);

				for (Field field : fields) {
					if (!isaStatic(field)) {
						String fieldName = field.getName();
						String column = translateField2Column(fieldName);
						columnFieldMap.put(column, field);
					}
				}

				ResultSetMetaData metaData = rs.getMetaData();
				int columnCount = metaData.getColumnCount();
				Map<String, String> columnClassMap = new HashMap<>();
				Field field;
				for (int i = 1; i <= columnCount; ++i) {
					String columnName = metaData.getColumnLabel(i).toLowerCase();
					String columnClassName = metaData.getColumnClassName(i);
					columnClassMap.put(columnName, columnClassName);
				}
				for (Map.Entry<String, String> m : columnClassMap.entrySet()) {
					String columnName = m.getKey();
					String columnClassName = m.getValue();
					Object value;
					if (columnClassName.toUpperCase().contains("[B")) {
						value = new DefaultLobHandler().getClobAsString(rs, columnName);
					} else {
						value = rs.getObject(columnName);
					}
					if (null != value) {
						field = columnFieldMap.get(columnName);
						if (null == field) {
//							logger.error("Class[" + clazz.getName() + "]中未发现数据库列[" + columnName + "]对应的字段!");
						} else {
							String fieldName = field.getName();

							Class<?> fieldType = field.getType();
							Class<?> valueType = value.getClass();
							boolean isDatabaseEnum = false;

						/*Class<?>[] interfaces = fieldType.getInterfaces();
						for (int j = 0; j < interfaces.length; j++) {
							if (interfaces[j].getName().contains("DatabaseEnum")) {
								isDatabaseEnum = true;
								break;
							}
						}*/
							Column column = field.getAnnotation(Column.class);
							if (fieldType != valueType) {
								if (column != null && column.isJson()) {
									try {
										value = SingletonObject.OBJECT_MAPPER.readValue((String) value, field.getType());
									} catch (Exception e) {
										throw new RuntimeException(e);
									}
								} else if (Clob.class.isAssignableFrom(valueType)) {
									try {
										value = new DefaultLobHandler().getClobAsString(rs, columnName);
									} catch (SQLException e) {
										value = "";
										logger.error("Class[" + clazz.getName() + "]中数据库列[" + columnName + "]CLOB字段转换错误 !");
									}
								} else {
									value = castValue(fieldType, valueType, value);
								}
							}

							try {
								clazz.getDeclaredMethod(getSetter(fieldName), fieldType).invoke(t, value);
							} catch (Exception var22) {
								logger.error("调用[" + clazz.getName() + "#" + fieldName + "]的Setter方法异常：" + var22.getMessage());
							}
						}
					}
				}


				return t;
			}
		};
	}

	private <C> ResultSetExtractor<List<C>> getListResultSetExtractor(Class<C> clazz) {
		return rs -> {
//			Class<C> entityClass = null;
//			try {
//				entityClass = (Class<C>) Class.forName(clazz.getName());
//			} catch (ClassNotFoundException e) {
//				logger.error(clazz.getName() + "类不存在 " + e.getMessage());
//				throw new NotFoundException(clazz.getName() + "类不存在 ");
//			}

			Field[] fields = clazz.getDeclaredFields();
			Map<String, Field> columnFieldMap = new HashMap<>(fields.length);

			Field field;
			for (Field item : fields) {
				field = item;
				if (!isaStatic(field)) {
					String fieldName = field.getName();
					String column = translateField2Column(fieldName);
					columnFieldMap.put(column, field);

				}
			}
			ResultSetMetaData metaData = rs.getMetaData();
			int columnCount = metaData.getColumnCount();
			Map<String, String> columnClassMap = new HashMap<>();

			for (int i = 1; i <= columnCount; ++i) {
				String columnName = metaData.getColumnLabel(i).toLowerCase();
				String columnClassName = metaData.getColumnClassName(i);
				columnClassMap.put(columnName, columnClassName);
			}
			List<C> result = new ArrayList<>();
			while (rs.next()) {
				C t;
				try {
					t = clazz.newInstance();
				} catch (Exception var23) {
					throw new RuntimeException(var23);
				}
				for (Map.Entry<String, String> m : columnClassMap.entrySet()) {
					String columnName = m.getKey();
					String columnClassName = m.getValue();
					Object value;
					if (columnClassName.toUpperCase().contains("[B")) {
						value = new DefaultLobHandler().getClobAsString(rs, columnName);
					} else {
						value = rs.getObject(columnName);
					}
					if (null != value) {
						field = columnFieldMap.get(columnName);
						if (null == field) {
//							System.out.println("Class[" + clazz.getName() + "]中未发现数据库列[" + columnName + "]对应的字段!");
						} else {
							String fieldName = field.getName();

							Class<?> fieldType = field.getType();
							Class<?> valueType = value.getClass();
							Column column = field.getAnnotation(Column.class);
							if (fieldType != valueType) {
								if (column != null && column.isJson()) {
									try {
										value = SingletonObject.OBJECT_MAPPER.readValue((String) value, field.getType());
									} catch (Exception e) {
										throw new RuntimeException(e);
									}
								} else if (Clob.class.isAssignableFrom(valueType)) {
									try {
										value = new DefaultLobHandler().getClobAsString(rs, columnName);
									} catch (SQLException e) {
										value = "";
//										System.out.println(("Class[" + clazz.getName() + "]中数据库列[" + columnName + "]CLOB字段转换错误 !"));
									}
								} else {
									value = castValue(fieldType, valueType, value);
								}
							}

							try {
								clazz.getDeclaredMethod(getSetter(fieldName), fieldType).invoke(t, value);
							} catch (Exception var22) {
								System.out.println(("调用[" + clazz.getName() + "#" + fieldName + "]的Setter方法异常：" + var22.getMessage()));
							}
						}
					}
				}
				result.add(t);
			}
			return result;
		};
	}

}
